#pragma once
#include "vector"
#include <cassert>
#include <cstring>
#include <algorithm>
#include <string>
//这个类猛猛抄的 用iovec的人也太多了吧 一个人写全部都他妈用
class buffer {
public:
    static constexpr const char *kCRLF = "\r\n";
    static constexpr size_t kInitialSize = 1024;

    explicit buffer(size_t initialSize = kInitialSize)
    : buffer_(initialSize), readerIndex_(0), writerIndex_(0) {
        assert(readableBytes() == 0);
        assert(writeableBytes() == kInitialSize);
        assert(prependableBytes() == 0);
    }

    void swap(buffer &rhs) {
        buffer_.swap(rhs.buffer_);
        std::swap(readerIndex_, rhs.readerIndex_);
        std::swap(writerIndex_, rhs.writerIndex_);
    }

    size_t readableBytes() const { return writerIndex_ - readerIndex_; }
    size_t writeableBytes() const { return buffer_.size() - writerIndex_; }
    size_t prependableBytes() const { return readerIndex_; }
    const char *peek() const { return begin() + readerIndex_; }

    void retrieve(size_t len) {
        assert(len <= readableBytes());
        if (len < readableBytes()) {
            readerIndex_ += len;
        } else {
            retrieveAll();
        }
    }

    void retrieveUntil(const char* end){
        assert(peek() <= end);
        assert(end <= beginWrite());
        retrieve(end - peek());
    }

    void retrieveAll() { readerIndex_ = writerIndex_ = 0; }

    std::string retrieveAsString(size_t len) {
        assert(len <= readableBytes());
        std::string ret(peek(), len);
        retrieve(len);
        return ret;
    }

    std::string retrieveAllAsString() {
        return retrieveAsString(readableBytes());
    }

    char *beginWrite() { return begin() + writerIndex_; }

    const char *beginWrite() const { return begin() + writerIndex_; }

    void ensureWriteableBytes(size_t len) {
        if (writeableBytes() < len) {
            makeSpace(len);
        }
        assert(writeableBytes() >= len);
    }

    void hasWritten(size_t len) {
        assert(len <= writeableBytes());
        writerIndex_ += len;
    }

    void append(const char *data, size_t len) {
        ensureWriteableBytes(len);
        std::copy(data, data + len, beginWrite());
        hasWritten(len);
    }

    void append(const std::string &data) { append(data.c_str(), data.size()); }

    ssize_t readFd(int fd);
    ssize_t writeFd(int fd);

    const char *findCRLF() const {
        const char *crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF + 2);
        return crlf == beginWrite() ? nullptr : crlf;
    }

    const char *findCRLF(const char *start) const {
        assert(peek() <= start);
        assert(start <= beginWrite());
        const char *crlf = std::search(start, beginWrite(), kCRLF, kCRLF + 2);
        return crlf == beginWrite() ? nullptr : crlf;
    }

private:
    char *begin() { return buffer_.data(); }
    const char *begin() const { return buffer_.data(); }

    void makeSpace(size_t len) {
        if (writeableBytes() + prependableBytes() < len) {
            buffer_.resize(writerIndex_ + len);
        } else {
            size_t readable = readableBytes();
            std::copy(begin() + readerIndex_, begin() + writerIndex_, begin());
            readerIndex_ = 0;
            writerIndex_ = readerIndex_ + readable;
            assert(readable == readableBytes());
        }
    }

    std::vector<char> buffer_;
    size_t readerIndex_;
    size_t writerIndex_;

};


